查看原文
其他

Go 1.17.6 发布关键词:iOS、macOS、HTTP2

Go 夜读 Go夜读 2022-01-07

2021年12月09日发布了安全更新 Go 1.17.5 和 Go 1.16.12, 包括 syscall 和 net/http 包的安全修复。

Severe HTTP/2 server Denial of Service (CVE-2021-44716)

今天(2022年01月07日) Go 又发布了 Go 1.17.6 和 Go 1.16.13。

本次更新包括哪些更新?


以下我们来看看详细分析:

  1. runtime: mallocs cause "base outside usable address space" panic when running on iOS 14 [1.17 backport] #48116

运行报错信息:

runtime: memory allocated by OS [0x2ac000000, 0x2b0000000) not in usable address space: base outside usable address space
fatal error: memory reservation exceeds address space limit

作者在 CL 修复中的描述:

在 iOS<14,地址空间被严格限制在 8 GiB,或 33 位。因此,页面分配程序还假定所有堆内存都位于该区域。这是特别必要的,因为页面分配器有一个与可用地址空间大小成比例的 PROT_NONE 映射,所以这使映射非常小。

但是从 iOS 14 开始,这个限制就放宽了,mmap 可以开始返回 <14 范围之外的地址。在现在这意味着在 iOS 14 和之后的版本中,当一个堆区域被映射到旧范围之外时,用户会在页面分配程序中遇到一个错误。

这个变化增加了 ios/arm64 的 heapAddrBits 到 40,同时使 ios/arm64 使用 64 位的 pagealloc 实现(保留和增量映射),以适应 iOS <14 和 14+。

一旦 iOS <14 被弃用,我们就可以移除这些异常,并像对待其他 arm64 平台一样对待 iOS /arm64。

在这里,这个更改还使 BaseChunkIdx 表达式更易于阅读。

var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*sys.GoosAix))

优化为:

var BaseChunkIdx = func() ChunkIdx {
 var prefix uintptr
 if pageAlloc64Bit != 0 {
  prefix = 0xc000
 } else {
  prefix = 0x100
 }
 baseAddr := prefix * pallocChunkBytes
 if sys.GoosAix != 0 {
  baseAddr += arenaBaseOffset
 }
 return ChunkIdx(chunkIndex(baseAddr))
}()

具体 CL 369737[1]

  1. runtime: race detector SIGABRT or SIGSEGV on macOS Monterey [1.17 backport] #50073

在 macOS 12 上,默认使用了一个新的 malloc 实现(nano),显然它保留了 0x600000000000-0x600020000000 的地址范围,这与 TSAN 用于 Go 的地址范围冲突。通过稍微改变地址范围来解决这个问题。

CL 370697[2]

  1. x/net/http2: http.Server.WriteTimeout does not fire if the http2 stream's window is out of space. [1.17 backport] #49921

http2 随机写调度程序不应键入 rst_stream 帧与数据帧,而是将它们视为控制帧。如果数据帧阻止队列,则可能存在死锁情况,因为如果发件人想要关闭它,它会发送 rst 帧,但如果客户端没有排出队列,则会卡住并且发件人无法完成。

@davecheney[4]给的例子:

package main

import (
 "io"
 "log"
 "net/http"
 "net/http/httptest"
 "strings"
 "time"
)

func handler(w http.ResponseWriter, r *http.Request) {
 data := strings.Repeat("x"1<<16)
 tick := time.NewTicker(100 * time.Millisecond) // 如果把 100 改为 1,则不会出现:`2022/01/07 10:04:54 wrote 0, err http2: stream closed`
 defer tick.Stop()
 for {
  select {
  case <-tick.C:
   n, err := io.WriteString(w, data)
   log.Printf("wrote %d, err %v", n, err)
   if err != nil {
    return
   }
  case <-r.Context().Done():
   log.Printf("context cancelled")
   return
  }
 }
}

func main() {
 sv := httptest.NewUnstartedServer(http.HandlerFunc(handler))
 sv.EnableHTTP2 = true
 sv.Config.WriteTimeout = 1 * time.Second
 sv.StartTLS()

 resp, err := sv.Client().Get(sv.URL + "/")
 if err != nil {
  log.Fatal(err)
 }
 defer resp.Body.Close()

 select {} // block forever
}

CL 375719[3]

不知道大家在使用 http2 的包有没有遇到这个问题呢?如果有,那你应该要感谢 @davecheney[4] ,因为 Go 团队有人提议将其放在 Go 1.18.1 来发布哦,是 @davecheney[4] 将其争取到 Go 1.17.6 就发布了。

其他内容,大家可以前往 Go 1.17.6 发布 notes[5] 中查阅。

[1]

CL 369737: https://go-review.googlesource.com/c/go/+/369737/

[2]

CL 370697: https://go-review.googlesource.com/c/go/+/370697/

[3]

CL 375719: https://go-review.googlesource.com/c/net/+/375719/

[4]

@davecheney: https://github.com/davecheney

[5]

Go 1.17.6 发布 notes: https://github.com/golang/go/issues?q=milestone%3AGo1.17.6+label%3ACherryPickApproved


往期更新

[Security] Go 1.17.1 and 1.16.8 are released!

[Security] Go 1.17.2 and 1.16.9 are released!

[Security] Go 1.17.3 and 1.16.10 are released!

[fixes] Go 1.17.4 and 1.16.11 are released!

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存